#!/usr/bin/env groovy

/*
# This pipeline can be tested by executing the following steps
* Create a branch with a non-existing version name such as "patch/4.1.2.3"
* Update all the pom files with the same version (4.1.2.3)
* Commit the pom files
* Tag the commit from above with "4.1.2.3"
* Push
* Update the "Filter by name (with regular expression)" field under "Branch Sources" (here)[https://ci.dhis2.org/view/dhis2-core/job/dhis2-core-stable/configure] to include your version.
  An example of such regular expression could be: ^2[.]\d+[.]\d+$|^2[.]\d+[.]\d+-(?i)embargoed$|^patch\/2[.]\d+[.]\d+$|^patch\/(2|4)[.]\d+[.]\d+[.]\d+$|^2[.]\d+[.]\d+[.]\d+$
* Schedule a build for your branch here... https://ci.dhis2.org/view/dhis2-core/job/dhis2-core-stable/

# Clean up
* Restore the regular expression previously updated to include your branch
* Delete the war file from S3: aws s3 rm s3://releases.dhis2.org/...
* Delete the docker image from the repository
*/

@Library('pipeline-library') _

pipeline {
    agent {
        label 'ec2-jdk17'
    }

    options {
        timeout(time: 60)
    }

    environment {
        MAVEN_OPTS = '-Xms1024m -Xmx4096m -Dmaven.wagon.http.retryHandler.class=standard -Dmaven.wagon.http.retryHandler.count=3 -Dmaven.wagon.httpconnectionManager.ttlSeconds=125'
        GITHUB_TOKEN = credentials('github-token')
        DHIS2_VERSION = readMavenPom(file: 'dhis-2/pom.xml').getVersion()
        DOCKER_IMAGE_NAME_DEV = "${DOCKER_HUB_OWNER}/core-dev"
        DOCKER_IMAGE_NAME = "${DOCKER_HUB_OWNER}/core"
        DOCKER_IMAGE_TAG = "${env.DHIS2_VERSION.replace('SNAPSHOT', 'rc')}"
        DOCKER_IMAGE_NAME_PUBLISH_TARGET = "${DOCKER_IMAGE_NAME}:${DOCKER_IMAGE_TAG}" // used to publish to Dockerhub
        // THIS MUST be kept in sync with the jib.from.image in ../dhis-2/dhis-web-server/pom.xml
        BASE_IMAGE = "tomcat:10.1.30-jre17"
    }

    stages {
        stage('Patch') {
            steps {
                echo 'Patching DHIS2 ...'
                sh './run-cve-patcher.sh'
            }
        }

        stage('Build') {
            steps {
                echo 'Building DHIS2 ...'
                script {
                    withMaven(options: [artifactsPublisher(disabled: true)]) {
                        sh 'mvn --threads 4 --batch-mode --no-transfer-progress clean install --file dhis-2/pom.xml --update-snapshots'
                    }
                }
            }
        }

        stage('Run api tests') {
            environment {
                RP_UUID = credentials('report-portal-access-uuid')
                RP_ENABLE = 'true'
                RP_ATTRIBUTES = "version:${env.GIT_BRANCH};"
                IMAGE_REPOSITORY = "$DOCKER_IMAGE_NAME_DEV"
                DOCKER_IMAGE_NAME_FULL = "${DOCKER_IMAGE_NAME_DEV}:${DOCKER_IMAGE_TAG}"
            }

            stages {
                stage('Build Docker image') {
                    steps {
                        withDockerRegistry([credentialsId: "docker-hub-credentials", url: ""]) {
                            withMaven(options: [artifactsPublisher(disabled: true)]) {
                                sh './dhis-2/build-docker-image.sh -t "${DOCKER_IMAGE_TAG}" -d'
                            }
                        }
                    }
                }

                stage('Run tests') {
                    steps {
                        script {
                            dir("dhis-2/dhis-test-e2e") {
                                sh "docker pull ${DOCKER_IMAGE_NAME_FULL}"
                                sh "DHIS2_IMAGE=${DOCKER_IMAGE_NAME_FULL} docker compose --file docker-compose.yml --file docker-compose.e2e.yml up --remove-orphans --exit-code-from test"
                            }
                        }
                    }

                    post {
                        always {
                            script {
                                dir("dhis-2/dhis-test-e2e") {
                                    archiveArtifacts artifacts: "coverage.csv", allowEmptyArchive: true
                                }
                            }
                        }

                        failure {
                            script {
                                dir("dhis-2/dhis-test-e2e") {
                                    sh "docker compose logs web > web-logs.txt"
                                    archiveArtifacts artifacts: "web-logs.txt"
                                }
                            }
                        }
                    }
                }
            }
        }

        stage('Publish images') {
            environment {
                IMAGE_REPOSITORY = "$DOCKER_IMAGE_NAME"
            }

            steps {
                script {
                    // Remove -rc suffix in case it's there, will be added later if needed.
                    oldImageTag = env.DOCKER_IMAGE_TAG.replace("-rc", "")

                    // If version contains more than 2 dots... It's a hotfix.
                    isHotfix = oldImageTag.length() - oldImageTag.replace(".", "").length() > 2

                    if (!isHotfix) {
                        oldImageTag = "$oldImageTag.0"
                    }

                    imageTag = oldImageTag.replaceFirst(/^2\./, "")

                    withDockerRegistry([credentialsId: "docker-hub-credentials", url: ""]) {
                        withMaven(options: [artifactsPublisher(disabled: true)]) {
                            if (env.DOCKER_IMAGE_TAG.endsWith("-rc")) {
                                imageTag = "$imageTag-rc"

                                // Release candidates don't need immutable and rolling tags.
                                sh "./dhis-2/build-docker-image.sh -t $imageTag -d"
                            } else {
                                sh "./dhis-2/build-docker-image.sh -t $imageTag"
                            }
                        }
                    }
                }
            }
        }

        stage('Sync WAR') {
            steps {
                echo 'Syncing WAR ...'
                sh 'curl "https://raw.githubusercontent.com/dhis2/dhis2-server-setup/master/ci/scripts/copy-war-s3.sh" -O'
                sh 'chmod +x copy-war-s3.sh'
                sh './copy-war-s3.sh stable ${GIT_BRANCH}'
            }
        }

        stage('Update stable.json') {
            when {
                buildingTag()
            }

            environment {
                DHIS2_RELEASES_REPO = "dhis2/dhis2-releases"
                GITHUB_EMAIL = 'apps@dhis2.org'
                GITHUB_USER = 'dhis2-bot'
            }

            steps {
                script {
                    dir('dhis2-releases') {
                        git url: "https://github.com/$DHIS2_RELEASES_REPO"

                        majorVersion = imageTag.split("\\.")[0]

                        sh """
                            ./tools/update-stable-json/update_stable_json.py \
                            --version $imageTag \
                            --war-path ${WORKSPACE}/dhis-2/dhis-web-server/target/dhis.war \
                            --war-url https://releases.dhis2.org/${majorVersion}/dhis2-stable-${imageTag}.war \
                            --release-date \$(date +%F) \
                            --json-file ./downloads/v1/versions/stable.json
                        """

                        withCredentials([
                            file(credentialsId: 'github-private-signing-key', variable: 'SIGNING_PRIVATE_KEY_PATH'),
                            file(credentialsId: 'github-public-signing-key', variable: 'SIGNING_PUBLIC_KEY_PATH')
                        ]) {
                            sh 'cp $SIGNING_PRIVATE_KEY_PATH ~/.ssh/signing_key'
                            sh 'cp $SIGNING_PUBLIC_KEY_PATH ~/.ssh/signing_key.pub'
                            sh 'chmod --changes 600 ~/.ssh/signing_key ~/.ssh/signing_key.pub'

                            sh 'git config user.email "$GITHUB_EMAIL"'
                            sh 'git config user.name "$GITHUB_USER"'
                            sh 'git config user.signingkey ~/.ssh/signing_key.pub'
                            sh 'git config commit.gpgSign true'
                            sh 'git config gpg.format ssh'

                            releasesBranch = "add-release-${imageTag}"

                            sh "git checkout -b $releasesBranch"
                            sh 'git add ./downloads/v1/versions/stable.json'
                            sh "git diff-index --quiet HEAD || git commit -S -m \"chore: add version $imageTag to stable.json\""
                            sh 'git push https://$GITHUB_TOKEN@github.com/$DHIS2_RELEASES_REPO'

                            sh "gh pr create --head $releasesBranch --fill-first --reviewer Philip-Larsen-Donnelly,dhis2/devops"
                            sh "gh pr merge $releasesBranch --merge"
                        }
                    }
                }
            }
        }

        stage('Update IM Play instance') {
            when {
                expression { !env.DOCKER_IMAGE_TAG.endsWith("rc") }
            }

            environment {
                HTTP = "http --check-status"
                IM_REPO_URL = "https://github.com/dhis2-sre/im-manager"
                IM_HOST = "https://api.im.dhis2.org"
                INSTANCE_URL = "https://play.im.dhis2.org"
                IMAGE_REPOSITORY = "core"
                IMAGE_PULL_POLICY = "Always"
                FLYWAY_MIGRATE_OUT_OF_ORDER = "true"
                FLYWAY_REPAIR_BEFORE_MIGRATION = "true"
                INSTANCE_TTL = "315360000"
                STARTUP_PROBE_FAILURE_THRESHOLD = "50"
                LIVENESS_PROBE_TIMEOUT_SECONDS = "5"
                READINESS_PROBE_TIMEOUT_SECONDS = "5"
                CORE_RESOURCES_REQUESTS_MEMORY = "2500Mi"
                PUBLIC = "true"
            }

            steps {
                echo 'Creating DHIS2 instance on IM...'
                script {
                    withCredentials([usernamePassword(credentialsId: 'dhis2-im-bot', passwordVariable: 'PASSWORD', usernameVariable: 'USER_EMAIL')]) {
                        dir('im-manager') {
                            gitHelper.sparseCheckout(IM_REPO_URL, "${gitHelper.getLatestTag(IM_REPO_URL)}", '/scripts')

                            def version = env.GIT_BRANCH
                            if (version.startsWith("patch/")) {
                                version = version.split("/")[1]
                            }
                            env.IMAGE_TAG = version
                            def instanceName = "stable-${version.replace(".", "-")}"

                            if (isHotfix) {
                                def endIndex = version.lastIndexOf(".")
                                version = version.substring(0, endIndex)
                            }

                            dir('scripts/databases') {
                                DATABASE_GROUP_NAME = 'test-dbs'
                                env.DATABASE_ID = im.findDatabaseId(DATABASE_GROUP_NAME, version)

                                if (!env.DATABASE_ID) {
                                    echo "Couldn't find database for $version"

                                    try {
                                        env.DATABASE_ID = im.uploadNewDatabase(DATABASE_GROUP_NAME, version)
                                    } catch (err) {
                                        echo "Couldn't download database for ${version}: ${err}"

                                        shortVersion = version.split('\\.').take(2).join('.')
                                        env.DATABASE_ID = im.findDatabaseId(DATABASE_GROUP_NAME, shortVersion)

                                        if (!env.DATABASE_ID) {
                                            echo "Couldn't find database for $shortVersion"

                                            env.DATABASE_ID = im.uploadNewDatabase(DATABASE_GROUP_NAME, shortVersion)
                                        }
                                    }
                                }

                                sh '[ -n "$DATABASE_ID" ]'
                                echo "Database: ${env.DATABASE_ID}"
                            }

                            dir('scripts/instances') {
                                description = "DHIS 2 stable branch ${env.GIT_BRANCH}"
                                sh "./findByName.sh play ${instanceName} | jq --exit-status 'has(\"id\")' && ./restart.sh \$(./findByName.sh play ${instanceName} | jq '.instances[] | select(.stackName==\"dhis2-core\") | .id') || ./deploy-dhis2.sh play ${instanceName} ${description}"
                                timeout(5) {
                                    waitFor.statusOk("${env.INSTANCE_URL}/${instanceName}")
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    post {
        failure {
            script {
                slack.sendMessage(
                    '#ff0000',
                    slack.buildUrl() + "\nLatest run on ${GIT_BRANCH} failed and needs investigation. :detective-duck:\nCommit: <${GIT_URL}/commit/${GIT_COMMIT}|${GIT_COMMIT}>",
                    'team-backend'
                )
            }
        }

        aborted {
            script {
                slack.sendTimedoutMessage()
            }
        }
    }
}
